package com.yoso.core.util;

import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.yoso.core.bo.CompareResult;
import io.swagger.v3.oas.annotations.media.Schema;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

public class CompareUtil {

	public static final String formatStr = "%s:原[%s]修改为[%s]";

	/**
	 * 比较对象的差异，得出描述
	 *
	 * @param history 修改之前
	 * @param current 当前
	 * @return java.lang.String
	 * @author shizejin
	 * @date 2023/4/28 15:48
	 */
	public static List<String> compareBean2DescriptionContent(Object history, Object current) {
		Assert.isTrue(history != null && current != null, "不能比较空对象");
		List<String> content = Lists.newArrayList();

		Class<?> cls = history.getClass();
		Assert.isTrue(cls == current.getClass(), "必须是同一个Class的实例对象");
		List<Class<?>> baseTypeClass = CollUtil.toList(String.class, Integer.class, Long.class, Double.class, Float.class, BigDecimal.class, LocalDate.class);
		// 只支持比较基本数据类型
		List<Field> historyFiledList = Arrays.stream(ReflectUtil.getFields(cls))
				.filter(f -> baseTypeClass.contains(f.getType())).collect(Collectors.toList());

		if (history instanceof CompareObject) {
			List<String> compareFieldList = ((CompareObject) history).compareFieldList();
			List<String> compareExcludeField = ((CompareObject) history).compareExcludeField();
			// 指定了比较字段
			if (CollUtil.isNotEmpty(compareFieldList)) {
				historyFiledList.removeIf(f -> !compareFieldList.contains(f.getName()));
			}
			// 指定了排除字段
			if (CollUtil.isNotEmpty(compareExcludeField)) {
				historyFiledList.removeIf(f -> compareExcludeField.contains(f.getName()));
			}
		}
		for (Field hisField : historyFiledList) {
			String name = hisField.getName();
			String hisValue = getDescriptionValue(ReflectUtil.getFieldValue(history, name));
			String currentValue = getDescriptionValue(ReflectUtil.getFieldValue(current, name));
//            比较
			if (ObjectUtil.equals(hisValue, currentValue)) {
				continue;
			}
			content.add(formatDiff(getFieldName(hisField), hisValue, currentValue));
		}
		return content;
	}


	/**
	 * 比较列表数据
	 * @param leftList  参照列表，一般为数据库数据
	 * @param rightList 操作列表，一般为请求数据
	 * @param keyFunction 列表的关联条件，一般为主键id或唯一的业务编码
	 * @return {@link CompareResult }<{@link T }>
	 * @author shizejin
	 * @date 2024/12/26
	 */
	public static <T> CompareResult<T> compare(List<T> leftList, List<T> rightList, Function<T, String> keyFunction) {
		CompareResult<T> compareSameResult = new CompareResult<>();
		Map<String, T> leftMap = CollStreamUtil.toMap(leftList, keyFunction, Function.identity());
		Map<String, T> rightMap = CollStreamUtil.toMap(rightList, keyFunction, Function.identity());
		Set<String> leftKeyList = leftMap.keySet();
		Set<String> rightKeyList = rightMap.keySet();
		Collection<String> same = CollUtil.intersection(leftKeyList, rightKeyList);
		compareSameResult.setLeftList(same.stream()
				.map(leftMap::get).collect(Collectors.toList()));
		compareSameResult.setRigthList(same.stream()
				.map(rightMap::get).collect(Collectors.toList()));
		List<T> addList = CollUtil.filter(rightList, right -> !leftMap.containsKey(keyFunction.apply(right)));
		compareSameResult.setAddList(addList);

		List<T> deleteList = CollUtil.filter(leftList, left -> !rightMap.containsKey(keyFunction.apply(left)));
		compareSameResult.setDeleteList(deleteList);
		compareSameResult.setKeyFunction(keyFunction);
		return compareSameResult;
	}

	/**
	 * 获取基本类型的字段
	 * @param history
	 * @return {@link List }<{@link String }>
	 * @author shizejin
	 * @date 2024/12/20
	 */
	public static List<String> getBaseTypeFieldNameList(Object history) {
		List<Class> baseTypeClass = CollUtil.toList(String.class, Integer.class, Long.class, Double.class, Float.class);
		return Arrays.stream(ReflectUtil.getFields(history.getClass())).filter(f -> baseTypeClass.contains(f.getClass())).map(Field::getName).collect(Collectors.toList());

	}


	/**
	 * 获取字段变化描述
	 *
	 * @param prefix 说明前缀
	 * @param oldStr 修改前的值
	 * @param newStr 修改后的值
	 * @return java.lang.String
	 * @author shizejin
	 * @date 2023/7/24 10:58
	 */
	public static String formatDiff(String prefix, Object oldStr, Object newStr) {
		return String.format(formatStr, prefix, getDescriptionValue(oldStr), getDescriptionValue(newStr));
	}

	/**
	 * 获取字段的描述
	 * 取 @Schema 中的description，其次取 fieldName
	 *
	 * @param field 字段
	 * @return java.lang.String
	 * @author shizejin
	 * @date 2023/4/28 16:17
	 */
	public static String getFieldName(Field field) {
		Schema annotation = field.getAnnotation(Schema.class);
		return Optional.ofNullable(annotation).map(Schema::description).orElse(field.getName());
	}

	/**
	 * 获取字符的说明（主要针对字符可能为空的）
	 * ep:  我吃了""个苹果、我吃了null个苹果 -> 我吃了空个苹果
	 * @param object 字符
	 * @return java.lang.String
	 * @author shizejin
	 * @date 2023/5/23 15:02
	 */
	public static String getDescriptionValue(Object object) {
		if (object instanceof String && StrUtil.isBlank(object.toString())) {
			return "空";
		}
		if (object instanceof LocalDate) {
			return ((LocalDate) object).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
		}
		return ObjectUtil.isNull(object) ? "空" : String.valueOf(object);
	}

	public interface CompareObject {
		/**
		 * 指定需要比较的字段
		 * @return {@link List }<{@link String }>
		 * @author shizejin
		 * @date 2024/12/20
		 */
		default List<String> compareFieldList(){return CollUtil.newArrayList();}

		/**
		 * 在比较时需要排除的字段
		 * @return {@link List }<{@link String }>
		 * @author shizejin
		 * @date 2024/12/20
		 */
		default List<String> compareExcludeField(){return CollUtil.newArrayList();}

	}

}
